Skip Headers

Oracle® Call Interface Programmer's Guide, 10g Release 2 (10.2) Part Number B14250-02 |
Home | Book List | Contents | Index | Master Index | Feedback

Previous | Next
| View PDF

# 12 Direct Path Loading

The direct path loading functions are used to load data from external files into tables and partitions.

This chapter contains these topics:

- Direct Path Loading Overview

- Direct Path Loading of Object Types

- Direct Path Loading in Pieces

- Direct Path Context Handles and Attributes for Object Types

## Direct Path Loading Overview

The direct path load interface enables an OCI application to access the direct path load engine of the Oracle database server to perform the functions of the Oracle SQL*Loader utility. This functionality provides the ability to load data from external files into either a table or a partition of a partitioned table.

Figure 12-1 Direct Path Loading

Description of "Figure 12-1 Direct Path Loading"

The OCI direct path load interface has the ability to load multiple rows by loading a direct path stream that contains data for multiple rows.

To use the direct path API, the client application performs the following steps:

1. Perform the OCI initialization.

2. Allocate a direct path context handle and set the attributes.

3. Supply the name of the object (table, partition, or sub-partition) to be loaded.

4. Describe the external datatypes of the columns of the object(s).

5. Prepare the direct path interface.

6. Allocate one or more column arrays.

7. Allocate one or more direct path streams.

8. Set entries in the column array to point to the input data value for each column.

9. Convert a column array to a direct path stream format.

10. Load the direct path stream.

11. Retrieve any errors that may have occurred.

12. Invoke the direct path finishing function.

13. Free handles and data structures.

14. Disconnect from the server.

Steps 8 through 11 can be repeated many times, depending on the data to be loaded.

A direct load operation requires that the object being loaded is locked to prevent DML on the object. Note that queries are lock-free and are allowed while the object is being loaded. The mode of the DML lock, and which DML locks are obtained depend upon the specification of the `OCI_ATTR_DIRPATH_PARALLEL` option, and if a partition or sub-partition load is being done as opposed to an entire table load.

See Also: "Direct Path Context Handle (OCIDirPathCtx) Attributes"

- For a table load, if the `OCI_ATTR_DIRPATH_PARALLEL` option is set to:

  - FALSE, then the table DML X-Lock is acquired.

  - TRUE, then the table DML S-Lock is acquired.

- For a partition load, if the `OCI_ATTR_DIRPATH_PARALLEL` option is set to:

  - FALSE, then the table DML SX-Lock and partition DML X-Lock is acquired.

  - TRUE, then the table DML SS-Lock and partition DML S-Lock is acquired.

### Datatypes Supported for Direct Path Loading

The following external datatypes are valid for scalar columns in a direct path load operation:

- SQLT_CHR

- SQLT_DAT

- SQLT_INT

- SQLT_UIN

- SQLT_FLT

- SQLT_BIN

- SQLT_NUM

- SQLT_PDN

- SQLT_DATE

- SQLT_TIMESTAMP

- SQLT_TIMESTAMP_TZ

- SQLT_TIMESTAMP_LTZ

- SQLT_INTERVAL_YM

- SQLT_INTERVAL_DS

The following external object datatypes are supported:

- SQLT_NTY - column objects (`FINAL` and `NOT FINAL`) and SQL string columns

- SQLT_REF - REF columns (`FINAL` and `NOT FINAL`)

The following table types are supported:

- Nested tables

- Object tables (`FINAL` and `NOT FINAL`)

  See Also: For information on setting or retrieving the datatype of a column, see "Accessing Column Parameter Attributes". For information on datatypes, see Table 3-2, "External Datatypes and Codes".

### Direct Path Handles

A direct path load corresponds to a direct path array insert operation. The direct path load interface uses the following handles to keep track of the objects loaded and the specification of the data operated on:

- direct path context

- direct path function context

- direct path column array

- direct path function context column array

- direct path stream

  See Also: "Direct Path Loading Handle Attributes" and all the descriptions of direct path attributes following

#### Direct Path Context

This handle must be allocated for each object, either a table or a partition of a partitioned table, being loaded. Because a `OCIDirPathCtx` handle is the parent handle of the `OCIDirPathFuncCtx`, `OCIDirPathColArray,` and `OCIDirPathStream` handles, freeing a `OCIDirPathCtx` handle frees its child handles also (although for good coding practices, free child handles individually before you free the parent handle).

A direct path context is allocated with OCIHandleAlloc(). Note that the parent handle of a direct path context is always the environment handle. A direct path context is freed with OCIHandleFree(). Include the header files in the first two lines in all direct path programs:

    ...
    #include <cdemodp0.h>
    #include <cdemodp.h>

    OCIEnv *envp;
    OCIDirPathCtx *dpctx;
    sword error;
    error = OCIHandleAlloc((dvoid *)envp, (dvoid **)&dpctx,
                        OCI_HTYPE_DIRPATH_CTX, (size_t)0,(dvoid **)0);
    ...
    error = OCIHandleFree(dpctx, OCI_HTYPE_DIRPATH_CTX);

#### OCI Direct Path Function Context

See Also: For more about the datatypes supported, see Oracle Database Application Developer's Guide - Object-Relational Features

This handle, of type `OCIDirPathFuncCtx`, is used to describe the following named type and REF columns:

- Column objects. The function context here describes the object type, which will be used as the default constructor to construct the object, and the object attributes of the constructor.

- REF columns. The function context here describes a single object table (optional) to reference row objects from, and the REF arguments that identify the row object.

- SQL string columns. The function context here describes a SQL string and its arguments to compute the value to be loaded into the column.

The handle type `OCI_HTYPE_DIRPATH_FN_CTX` is passed to `OCIHandleAlloc()` to indicate that a function context is to be allocated, as in the following example.

    OCIDirPathCtx *dpctx;       /* direct path context */
    OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
    sword error;

    error = OCIHandleAlloc((dvoid *)dpctx, (dvoid **)&dpfnctx,
                           OCI_HTYPE_DIRPATH_FN_CTX,
                           (size_t)0, (dvoid **)0);

Note that the parent handle of a direct path function context is always the direct path context handle. A direct path function context handle is freed with:

    error = OCIHandleFree(dpfnctx, OCI_HTYPE_DIRPATH_FN_CTX);

#### Direct Path Column Array and Direct Path Function Column Array

These handles are used to present an array of rows to the direct path interface. A row is represented by three arrays: column values, column lengths, and column flags. Methods used on a column array include: allocate the array handle and set or get values corresponding to an array entry.

Both handles share the same data structure, `OCIDirPathColArray`. But these column array handles differ in parent handles and handle types.

A direct path column array handle is allocated with `OCIHandleAlloc()`. The following code fragment shows explicit allocation of the direct path column array handle:

    OCIDirPathCtx *dpctx;      /* direct path context */
    OCIDirPathColArray *dpca;  /* direct path column array */
    sword error;
    error = OCIHandleAlloc((dvoid *)dpctx, (dvoid **)&dpca,
                   OCI_HTYPE_DIRPATH_COLUMN_ARRAY,
                   (size_t)0, (dvoid **)0);

A direct path column array handle is freed with `OCIHandleFree()`.

    error = OCIHandleFree(dpca, OCI_HTYPE_DIRPATH_COLUMN_ARRAY);

A direct path function column array handle is allocated in almost the same way:

    OCIDirPathFuncCtx *dpfnctx;   /* direct path function context */
    OCIDirPathColArray *dpfnca;   /* direct path function column array */
    sword error;
    error = OCIHandleAlloc((dvoid *)dpfnctx, (dvoid **)&dpfnca,
                            (ub4)OCI_HTYPE_DIRPATH_FN_COL_ARRAY,
                            (size_t)0, (dvoid **)0);

A direct path function column array is freed with `OCIHandleFree()`:

    error = OCIHandleFree(dpfnca, OCI_HTYPE_DIRPATH_FN_COL_ARRAY);

Freeing a `OCIDirPathColArray` handle also frees the column array associated with the handle.

#### Direct Path Stream

This handle is used by the conversion operation, OCIDirPathColArrayToStream(), and by the load operation, OCIDirPathLoadStream().

Direct path stream handles is allocated by the client with `OCIHandleAlloc()`. The structure of a `OCIDirPathStream` handle can be thought of as a pair in the form (buffer, buffer length).

A direct path stream is a linear representation of Oracle table data. The conversion operations always append to the end of the stream. Load operations always start from the beginning of the stream. After a stream is completely loaded, the stream must be reset by calling `OCIDirPathStreamReset()`.

The following example shows a direct path stream handle allocated with `OCIHandleAlloc()`. The parent handle is always an `OCIDirPathCtx` handle:

    OCIDirPathCtx *dpctx;    /* direct path context */
    OCIDirPathStream *dpstr; /* direct path stream */
    sword error;
    error = OCIHandleAlloc((dvoid *)dpctx, (dvoid **)&dpstr,
                   OCI_HTYPE_DIRPATH_STREAM, (size_t)0,(dvoid **)0);

A direct path stream handle is freed using `OCIHandleFree()`.

    error = OCIHandleFree(dpstr, OCI_HTYPE_DIRPATH_STREAM);

Freeing an `OCIDirPathStream` handle also frees the stream buffer associated with the handle.

### Direct Path Interface Functions

The functions listed in this section are used with the direct path load interface.

See Also: Detailed descriptions of each function can be found in "Direct Path Loading Functions"

Operations on the direct path context are performed by the functions in Table 12-1.

Table 12-1 Direct Path Context Functions

Function | Purpose
--- | ---
OCIDirPathAbort() | Aborts a direct path operation
OCIDirPathDataSave() | Executes a data savepoint
OCIDirPathFinish() | Commits the loaded data
OCIDirPathFlushRow() | Flushes a partially loaded row from server. This function is deprecated.
OCIDirPathLoadStream() | Loads data that has been converted to direct path stream format
OCIDirPathPrepare() | Prepares direct path interface to convert or load rows

Operations on the direct path column array are performed by the functions in Table 12-2, "Direct Path Column Array Functions".

Table 12-2 Direct Path Column Array Functions

Function | Purpose
--- | ---
OCIDirPathColArrayEntryGet() | Gets a specified entry in a column array
OCIDirPathColArrayEntrySet() | Sets a specified entry in a column array to a specific value
OCIDirPathColArrayRowGet() | Gets the base row pointers for a specified row number
OCIDirPathColArrayReset() | Resets the row array state
OCIDirPathColArrayToStream() | Converts from a column array format to a direct path stream format

Operations on the direct path stream are performed by the function OCIDirPathStreamReset() which resets the direct stream state.

### Limitations and Restrictions of the Direct Path Load Interface

The direct path load interface has the following limitations that are the same as SQL*Loader:

- Triggers are not supported.

- Referential integrity constraints are not supported.

- Clustered tables are not supported.

- Loading of remote objects is not supported.

- `LONGs` must be specified last.

- SQL strings that return LOBs, objects, or collections are not supported.

- Loading of `VARRAY` columns is not supported.

- All partitioning columns must come before any LOBs. This is because we need to determine what partition the LOB will go into before we start writing to it.

### Direct Path Load Example for Scalar Columns

Here are some code examples for scalar columns.

#### Data Structures Used in Direct Path Loading Example

The following data structure is used in the example.

    /* load control structure */
    struct loadctl
    {
      ub4                 nrow_ctl;            /* number of rows in column array */
      ub2                 ncol_ctl;         /* number of columns in column array */
      OCIEnv             *envhp_ctl;                       /* environment handle */
      OCIServer          *srvhp_ctl;                            /* server handle */
      OCIError           *errhp_ctl;                             /* error handle */
      OCIError           *errhp2_ctl;                /* yet another error handle */
      OCISvcCtx          *svchp_ctl;                          /* service context */
      OCISession         *authp_ctl;                   /* authentication context */
      OCIParam           *colLstDesc_ctl;        /* column list parameter handle */
      OCIDirPathCtx      *dpctx_ctl;                      /* direct path context */
      OCIDirPathColArray *dpca_ctl;           /* direct path column array handle */
      OCIDirPathColArray *dpobjca_ctl;          /* dp column array handle for obj*/
      OCIDirPathColArray *dpnestedobjca_ctl;  /* dp col array hndl for nested obj*/
      OCIDirPathStream   *dpstr_ctl;                /* direct path stream handle */
      ub1                *buf_ctl;    /* pre-alloc'd buffer for out-of-line data */
      ub4                 bufsz_ctl;                 /* size of buf_ctl in bytes */
      ub4                 bufoff_ctl;                     /* offset into buf_ctl */
      ub4                *otor_ctl;                  /* Offset to Recnum mapping */
      ub1                *inbuf_ctl;                 /* buffer for input records */
      struct pctx         pctx_ctl;                     /* partial field context */
      boolean             loadobjcol_ctl;             /* load to obj col(s)? T/F */
    };

The header file `cdemodp.h`, which is from the `demo` directory, defines several structs:

    #ifndef cdemodp_ORACLE
    # define cdemodp_ORACLE

    # include <oratypes.h>

    # ifndef externdef
    #  define externdef
    # endif

    /* External column attributes */
    struct col
    {
      text *name_col;                                             /* column name */
      ub2   id_col;                                            /* column load id */
      ub2   exttyp_col;                                         /* external type */
      text *datemask_col;                             /* datemask, if applicable */
      ub1   prec_col;                                /* precision, if applicable */
      sb1   scale_col;                                   /* scale, if applicable */
      ub2   csid_col;                                        /* character set id */
      ub1   date_col;            /* is column a chrdate or date? 1=TRUE. 0=FALSE */
      struct obj * obj_col;          /* description of object, if applicable */
    #define COL_OID 0x1                                         /* col is an OID */
      ub4   flag_col;
    };

    /* Input field descriptor
     * For this example (and simplicity),
     * fields are strictly positional.
     */
    struct fld
    {
      ub4  begpos_fld;                             /* 1-based beginning position */
      ub4  endpos_fld;                             /* 1-based ending    position */
      ub4  maxlen_fld;                       /* max length for out of line field */
      ub4    flag_fld;
    #define FLD_INLINE            0x1
    #define FLD_OUTOFLINE         0x2
    #define FLD_STRIP_LEAD_BLANK  0x4
    #define FLD_STRIP_TRAIL_BLANK 0x8
    };

    struct obj
    {
      text               *name_obj;                                /* type  name*/
      ub2                 ncol_obj;              /* number of columns in col_obj*/
      struct col         *col_obj;                          /* column attributes*/
      struct fld         *fld_obj;                           /* field descriptor*/
      ub4                 rowoff_obj;  /* current row offset in the column array*/
      ub4                 nrows_obj;              /* number of rows in col array*/
      OCIDirPathFuncCtx  *ctx_obj;       /* Function context for this obj column*/
      OCIDirPathColArray *ca_obj;           /* column array  for this obj column*/
      ub4                 flag_obj;                              /* type of obj */
    #define OBJ_OBJ  0x1                                             /* obj col */
    #define OBJ_OPQ  0x2                                  /* opaque/sql str col */
    #define OBJ_REF  0x4                                             /* ref col */
    };

    struct tbl
    {
      text        *owner_tbl;                                     /* table owner */
      text        *name_tbl;                                       /* table name */
      text        *subname_tbl;                        /* subname, if applicable */
      ub2          ncol_tbl;                     /* number of columns in col_tbl */
      text        *dfltdatemask_tbl;            /* table level default date mask */
      struct col  *col_tbl;                                 /* column attributes */
      struct fld  *fld_tbl;                                  /* field descriptor */
      ub1          parallel_tbl;                         /* parallel: 1 for true */
      ub1          nolog_tbl;                          /* no logging: 1 for true */
      ub4          xfrsz_tbl;                   /* transfer buffer size in bytes */
      text         *objconstr_tbl;   /* obj constr/type if loading a derived obj */
    };

    struct sess                        /* options for a direct path load session */
    {
      text        *username_sess;                                        /* user */
      text        *password_sess;                                    /* password */
      text        *inst_sess;                            /* remote instance name */
      text        *outfn_sess;                                /* output filename */
      ub4          maxreclen_sess;          /* max size of input record in bytes */
    };

    #endif                                              /* cdemodp_ORACLE */

#### Outline of an Example of a Direct Path Load for Scalar Columns

The following sample code illustrates the use of several of the OCI direct path interfaces. It is not a complete code example.

The init_load function performs a direct path load using the direct path API on the table described by tblp. The loadctl structure given by ctlp has an appropriately initialized environment and service context. A connection has been made to the server.

    STATICF void
    init_load(ctlp, tblp)
    struct loadctl *ctlp;
    struct tbl     *tblp;
    {
      struct  col   *colp;
      struct  fld   *fldp;
      sword          ociret;                       /* return code from OCI calls */
      OCIDirPathCtx *dpctx;                               /* direct path context */
      OCIParam      *colDesc;                     /* column parameter descriptor */
      ub1            parmtyp;
      ub1           *timestamp = (ub1 *)0;
      ub4            size;
      ub4            i;
      ub4            pos;

      /* allocate and initialize a direct path context */
      /* See cdemodp.c for the definition of OCI_CHECK */
      OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp,
                OCIHandleAlloc((dvoid *)ctlp->envhp_ctl,
                               (dvoid **)&ctlp->dpctx_ctl,
                               (ub4)OCI_HTYPE_DIRPATH_CTX,
                               (size_t)0, (dvoid **)0));

      dpctx = ctlp->dpctx_ctl;                                      /* shorthand */

      OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp,
                OCIAttrSet((dvoid *)dpctx, (ub4)OCI_HTYPE_DIRPATH_CTX,
                           (dvoid *)tblp->name_tbl,
                           (ub4)strlen((const char *)tblp->name_tbl),
                           (ub4)OCI_ATTR_NAME, ctlp->errhp_ctl));

Additional attributes, such as `OCI_ATTR_SUB_NAME` and `OCI_ATTR_SCHEMA_NAME`, are also set here. After the attributes have been set, prepare the load.

    OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp,
                OCIDirPathPrepare(dpctx, ctlp->svchp_ctl, ctlp->errhp_ctl));

##### Allocate the Column Array and Stream Handles.

Note that the direct path context handle is the parent handle for the column array and stream handles. Also note that errors are returned with the environment handle associated with the direct path context.

    OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp,
                OCIHandleAlloc((dvoid *)ctlp->dpctx_ctl, (dvoid **)&ctlp->dpca_ctl,
                               (ub4)OCI_HTYPE_DIRPATH_COLUMN_ARRAY,
                               (size_t)0, (dvoid **)0));

      OCI_CHECK(ctlp->envhp_ctl, OCI_HTYPE_ENV, ociret, ctlp,
                OCIHandleAlloc((dvoid *)ctlp->dpctx_ctl,(dvoid **)&ctlp->dpstr_ctl,
                               (ub4)OCI_HTYPE_DIRPATH_STREAM,
                               (size_t)0, (dvoid **)0));

##### Get Number of Rows and Columns

Get number of rows and columns in the column array just allocated.

    OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp,
                OCIAttrGet(ctlp->dpca_ctl, (ub4)OCI_HTYPE_DIRPATH_COLUMN_ARRAY,
                           &ctlp->nrow_ctl, 0, OCI_ATTR_NUM_ROWS,
                           ctlp->errhp_ctl));

       OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp,
                OCIAttrGet(ctlp->dpca_ctl, (ub4)OCI_HTYPE_DIRPATH_COLUMN_ARRAY,
                           &ctlp->ncol_ctl, 0, OCI_ATTR_NUM_COLS,
                           ctlp->errhp_ctl));

##### Set Input Data Fields

Set the input data fields to their corresponding data columns.

    ub4            rowoff;                          /* column array row offset */
    ub4            clen;                                      /* column length */
    ub1            cflg;                                  /* column state flag */
    ub1           *cval;                             /* column character value */

    OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp,
                OCIDirPathColArrayEntrySet(ctlp->dpca_ctl, ctlp->errhp_ctl,
                                           rowoff, colp->id_col,
                                           cval, clen, cflg));

##### Reset Column Array State

Reset column array state in case a previous conversion needed to be continued or a row is expecting more data.

    (void) OCIDirPathColArrayReset(ctlp->dpca_ctl, ctlp->errhp_ctl);

##### Reset the Stream State

Reset the stream state to start a new stream. Otherwise, data in the stream is appended to existing data.

    (void) OCIDirPathStreamReset(ctlp->dpstr_ctl, ctlp->errhp_ctl);

##### Convert Data to Stream Format

After inputting the data, convert the data in the column array to stream format and filter out any bad records.

    ub4            rowcnt;                   /* number of rows in column array */
    ub4            startoff;         /* starting row offset into column array  */

    /* convert array to stream, filter out bad records */
    ocierr = OCIDirPathColArrayToStream(ctlp->dpca_ctl, ctlp->dpctx_ctl,
                                            ctlp->dpstr_ctl, ctlp->errhp_ctl,
                                            rowcnt, startoff);

##### Load the Stream.

Note that the position in the stream is maintained internally to the stream handle, along with offset information for the column array which produced the stream. When the conversion to stream format is done, the data is appended to the stream. It is the responsibility of the caller to reset the stream when appropriate. On errors, the position is moved to the next row, or the end of the stream if the error occurs on the last row. The next `OCIDirPathLoadStream()` call starts on the next row, if any. If a `OCIDirPathLoadStream()` call is made, and the end of a stream has been reached, `OCI_NO_DATA` is returned.

    /* load the stream */
    ociret = OCIDirPathLoadStream(ctlp->dpctx_ctl, ctlp->dpstr_ctl,
                ctlp->errhp_ctl);

##### Finish the Direct Path Load

    /* free up server data structures for the load */
    OCI_CHECK(ctlp->errhp_ctl, OCI_HTYPE_ERROR, ociret, ctlp,
              OCIDirPathFinish(ctlp->dpctx_ctl, ctlp->errhp_ctl));

##### Free the Direct Path Handles

Free all the direct path handles allocated. Note that direct path column array and stream handles are freed before the parent direct path context handle is freed.

    ociret = OCIHandleFree((dvoid *)ctlp->dpca_ctl,
                               OCI_HTYPE_DIRPATH_COLUMN_ARRAY);
    ociret = OCIHandleFree((dvoid *)ctlp->dpstr_ctl,
                               OCI_HTYPE_DIRPATH_STREAM);
    ociret = OCIHandleFree((dvoid *)ctlp->dpctx_ctl,
                              OCI_HTYPE_DIRPATH_CTX);

### Using a Date Cache in Direct Path Loading of Dates in OCI

The date cache feature provides improved performance when loading Oracle date and timestamp values that require datatype conversions in order to be stored in the table.

This feature is specifically targeted to loads where the same input date values are loaded over and over again. Date conversions are very expensive and can account for a large percentage of the total load time, especially if there are multiple date columns loaded. This feature can significantly improve performance by reducing the actual number of date conversions done when many duplicate date values occur in the input data. However, date cache will only improve performance when many duplicate input date values are loaded into date columns (the word date in this chapter applies to all the date and timestamp datatypes).

When you explicitly specify the date cache size, the date cache feature will not be disabled, by default. To override this behavior, set `OCI_ATTR_DIRPATH_DCACHE_DISABLE` to 1. Otherwise, the cache will continue to be searched to avoid date conversions. However any misses will be converted the hard way.

Query the attributes `OCI_ATTR_DIRPATH_DCACHE_NUM`, `OCI_ATTR_DIRPATH_DCACHE_MISSES`, `OCI_ATTR_DIRPATH_DCACHE_HITS` and then tune the cache size for future loads.

You can lower the cache size when there are no misses and the number of elements in the cache is less than the cache size. The cache size can be increased if there are many cache misses and relatively few hits. Note that increasing the cache size too much can cause other problems, like paging or exhausting memory. If increasing the cache size does not improve performance, the feature should not be used.

The date cache feature can be explicitly and totally disabled by setting the date cache size to 0.

The following OCI direct path context attributes support this functionality:

#### OCI_ATTR_DIRPATH_DCACHE_SIZE

This attribute, when not equal to 0, sets the date cache size (in elements) for a table. For example, if the date cache size is set to 200, then at most 200 unique date or timestamp values can be stored in the cache. The date cache size cannot be changed once `OCIDirPathPrepare()` has been called. The default value is 0, meaning a date cache will not be created for a table. A date cache will be created for a table only if one or more date or timestamp values are loaded that require datatype conversions and the attribute value is nonzero.

#### OCI_ATTR_DIRPATH_DCACHE_NUM

This attribute is used to query the current number of entries in a date cache.

#### OCI_ATTR_DIRPATH_DCACHE_MISSES

This attribute is used to query the current number of date cache misses. If this number is high, consider tuning the application with a larger date cache size. If increasing the date cache size doesn't cause this number to decrease significantly, the date cache should probably not be used. Date cache misses are expensive, due to hashing and look up times.

#### OCI_ATTR_DIRPATH_DCACHE_HITS

This attribute is used to query the number of date cache hits. This number should be relatively large in order to see any benefit of using the date cache support.

#### OCI_ATTR_DIRPATH_DCACHE_DISABLE

Setting this attribute to 1 indicates that the date cache should be disabled if the size is exceeded. Note that this attribute cannot be changed or set after `OCIDirPathPrepare()` has been called.

The default (= 0) is to not disable a cache on overflow. When not disabled, the cache is searched to avoid conversions, but overflow input date value entries will not be added to the date cache, and will be converted using expensive date conversion functions. Again, excessive date cache misses can cause the application to run slower than not using the date cache at all.

This attribute can also be queried to see if a date cache has been disabled due to overflow.

See Also: "Direct Path Context Handle (OCIDirPathCtx) Attributes"

## Direct Path Loading of Object Types

The use of the direct path function contexts to load various non-scalar types is discussed in this section.

The non-scalar types are:

- nested tables

- object tables (`FINAL` and `NOT FINAL`)

- column objects (`FINAL` and `NOT FINAL`)

- REF columns (`FINAL` and `NOT FINAL`)

- SQL string columns

  See Also: Table B-1, "OCI Demonstration Programs" for a listing of the programs demonstrating direct path loading that are available with your Oracle installation.

### Direct Path Loading of Nested Tables

Nested tables are stored in a separate table. Using the direct path loading API, a nested table is loaded separately from its parent table with a foreign key, called a `SETID`, to link the two tables together.

Note: Currently, the `SETID`s must be user-supplied, and are not system-generated. When loading the parent and child tables separately, it is possible that orphaned children can be created when the rows are inserted in the child table, but the corresponding parent row is not inserted in the parent table. It is also possible to insert a parent row in the parent table, but that the child rows are not inserted in the child table and therefore it will have missing children.

#### Describing a Nested Table Column and Its Nested Table

Note: Steps that are different from loading scalar data are in italics.

Loading the parent table with a nested table column is a separate action from loading the child nested table.

- To load the parent table with a nested-table column:

  1. Describe the parent table and its columns as usual, except:

  2. When describing the nested-table column, this is the column that stores the SETIDs. Its external datatype is SQLT_CHR if the SETID s in the data file are in characters, SQLT_BIN if binary.

- To load the nested table (child):

  1. Describe the nested table and its columns as usual.

  2. The SETID column is required.

     - Set its OCI_ATTR_NAME using a dummy name (for example "setid") because the API does not expect you to know its system name.

     - Set the column attribute with OCI_ATTR_DIRPATH_SID to indicate that this is a SETID column:

           ub1 flg = 1;
           sword error;

           error = OCIAttrSet((dvoid *)colDesc,
                              OCI_DTYPE_PARAM,
                              (dvoid *)&flg, (ub4)0,
                              OCI_ATTR_DIRPATH_SID, ctlp->errhp_ctl);

### Direct Path Loading of Column Objects

A column object is a table column that is defined as an object. Currently only the default constructor, which consists of all of the constituent attributes, is supported.

#### Describing a Column Object

To describe a column object and its object attributes, use a direct path function context. Describing a column object requires setting its object constructor. Describing object attributes is similar to describing a list of scalar columns.

To describe a column object:

Note: Nested column objects are supported. The steps here are similar to that of describing a list of scalar columns to be loaded for a table. Steps that are new are in italics.

1. Allocate a parameter handle on the column object with `OCI_DTYPE_PARAM`. This parameter handle is used to set the column's external attributes.

2. Set the column name and its other external column attributes (for example, maximum data size, precision, scale).

3. Set the external type as SQLT_NTY (named type) with OCI_ATTR_DATA_TYPE.

4. Allocate a direct path function context handle. This context will be used to describe the column's object type and attributes:

    OCIDirPathFuncCtx *dpfnctx  /* direct path function context */;
    sword error;
    error = OCIHandleAlloc((dvoid *)dpctx, (dvoid **)&dpfnctx,
                   OCI_HTYPE_DIRPATH_FN_CTX,
                   (size_t)0, (dvoid **)0);

5. Set the column's object type name (for example, "Employee") with OCI_ATTR_NAME in the function context:

    OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
    text *obj_type;   /* column object's object type */
    sword error;

    error = OCIAttrSet((dvoid *)dpfnctx,
                       OCI_HTYPE_DIRPATH_FN_CTX,
                       (dvoid *)obj_type, (ub4)strlen((const char *)obj_type),
                       OCI_ATTR_NAME, ctlp->errhp_ctl);

6. Set the expression type, OCI_ATTR_DIRPATH_EXPR_TYPE, to be OCI_DIRPATH_EXPR_OBJ_CONSTR. This indicates that the expression set with OCI_ATTR_NAME will be used as the default object constructor:

    OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
    ub1 expr_type = OCI_DIRPATH_EXPR_OBJ_CONSTR;
    sword error;

    error = OCIAttrSet((dvoid *)dpfnctx,
                       OCI_HTYPE_DIRPATH_FN_CTX,
                       (dvoid *)&expr_type, (ub4)0,
                       OCI_ATTR_DIRPATH_EXPR_TYPE,
                       ctlp->errhp_ctl);

7. Set the number of columns or object attributes that will be loaded for this column object using OCI_ATTR_NUM_COLS.

8. Get the column/attribute parameter list for the function context `OCIDirPathFuncCtx`.

9. For each object attribute:

1. Get the column descriptor for the object attribute with `OCI_DTYPE_PARAM`.

2. Set the attribute's column name with `OCI_ATTR_NAME`.

3. Set the external column type (the type of the data that will be passed to the direct path API) with `OCI_ATTR_DATA_TYPE`.

4. Set any other external column attributes (maximum data size, precision, scale, and so on.)

5. If this attribute column is a column object, then do steps 3-10 for its object attributes.

6. Free the handle to the column descriptor.

10. Set the function context `OCIDirPathFuncCtx` that was created in step 4 into the parent column object's parameter handle with OCI_ATTR_DIRPATH_FN_CTX.

#### Allocating the Array Column for the Column Object

When loading a column object, the data for its object attributes will be loaded into a separate column array created just for that object. A child column array is allocated for each column object, whether it is nested or not. Each row of object attributes in the child column array maps back to the corresponding non-NULL row of its parent column object in the parent column array.

Use the column object's direct path function context handle and column array type `OCI_HTYPE_DIRPATH_FN_COL_ARRAY`.

To allocate a child column array for a column object:

    OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
    OCIDirPathColArray *dpfnca;   /* direct path function column array */
    sword error;

    error = OCIHandleAlloc((dvoid *)dpfnctx, (dvoid **)&dpfnca,
                           OCI_HTYPE_DIRPATH_FN_COL_ARRAY,
                           (size_t)0, (dvoid **)0);

#### Loading Column Object Data into the Column Array

If a column is scalar, its value is set in the column array by passing the address of its value to `OCIDirPathColArrayEntrySet()`. And if a column is an object, the address of its child column array handle is passed instead. The child column array will contain the data of the object attributes.

To load data into a column object:

Note: Steps that are different from loading scalar data are in italics.

(Start.) For each column object:

1. If the column is non-NULL:

   1. For each of its object attribute columns:

      If an object attribute is a nested column object, then go to (Start.) and do this entire procedure recursively.

      Set the data in the child column array using OCIDirPathColArrayEntrySet().

   2. Set the column object's data in the column array by passing the address of its child column array handle to `OCIDirPathColArrayEntrySet()`.

2. Else if the column is NULL:

   - Set the column object's data in the column array by passing a NULL address for the data, a length of 0, and an `OCI_DIRPATH_COL_NULL` flag to `OCIDirPathColArrayEntrySet()`.

#### OCI_DIRPATH_COL_ERROR

This value is passed to `OCIDirPathColArrayEntry()` to indicate that the current column array row should be ignored. A typical use of this value is to back out all previous conversions for a row when an error occurs providing more data for a partial column (`OCI_NEED_DATA` was returned from the previous `OCIDirPathColArrayToStream()` call). Any previously converted data placed in the output stream buffer for the current row is removed. Conversion then continues with the next row in the column array. The purged row is counted in the converted row count.

When `OCI_DIRPATH_COL_ERROR` is specified, the current row is ignored, as well as are any corresponding rows in any child column arrays referenced, starting from the top level column array row. Any `NULL` child column array references are ignored when moving all referenced child column arrays to their next row.

### Direct Path Loading of SQL String Columns

A column value can be computed by a SQL string. SQL strings can be used for scalar column types. SQL strings cannot be used for object types, but can be used for object attributes of scalar column types. They cannot be used for nested tables and LONGs.

A SQL expression is represented to the direct path API using the `OCIDirPathFuncCtx`. Its `OCI_ATTR_NAME` value will be the SQL string with the parameter list of the named bind variables for the expression.

The bind variable namespace is limited to a column's SQL string. The same bind variable name can be used for multiple columns, but any arguments with the same name only apply to the SQL string of that column.

If a SQL string of a column contains multiple references to a bind variable and multiple arguments are specified for that name, all of the values must be the same, otherwise the results are undefined. Only one argument is actually required for this case, as all references to the same bind variable name in a particular SQL expression will be bound to that single argument.

A SQL string example is:

    substr(substr(:string, :offset, :length), :offset, :length)

Things to note about this example are:

- SQL expressions can be nested.

- Bind variable names can be repeated within the expression.

#### Describing a SQL String Column

Note: Steps that are different from loading scalar data are in italics.

1. Allocate a parameter handle on the SQL string column with `OCI_DTYPE_PARAM`. This parameter handle is used to set the column's external attributes.

2. Set the column name and its other external column attributes (for example, maximum data size, precision, scale).

3. Set the SQL string column's external type as SQLT_NTY with OCI_ATTR_DATA_TYPE.

4. Allocate a direct path function context handle. This context will be used to describe the arguments of the SQL string.

       OCIDirPathFuncCtx *dpfnctx  /* direct path function context */;
       sword error;
       error = OCIHandleAlloc((dvoid *)dpctx, (dvoid **)&dpfnctx,
                      OCI_HTYPE_DIRPATH_FN_CTX,
                      (size_t)0, (dvoid **)0);

5. Set the column's SQL string in OCI_ATTR_NAME in the function context.

       OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
       text *sql_str;   /* column's SQL string expression */
       sword error;

       error = OCIAttrSet((dvoid *)dpfnctx,
                          OCI_HTYPE_DIRPATH_FN_CTX,
                          (dvoid *)sql_str, (ub4)strlen((const char *)sql_str),
                          OCI_ATTR_NAME, ctlp->errhp_ctl);

6. Set the expression type, OCI_ATTR_DIRPATH_EXPR_TYPE, to be OCI_DIRPATH_EXPR_SQL. This indicates that the expression set with OCI_ATTR_NAME will be used as the SQL string to derive the value from.

       OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
       ub1 expr_type = OCI_DIRPATH_EXPR_SQL;
       sword error;

       error = OCIAttrSet((dvoid *)dpfnctx,
                          OCI_HTYPE_DIRPATH_FN_CTX,
                          (dvoid *)&expr_type, (ub4)0,
                          OCI_ATTR_DIRPATH_EXPR_TYPE, ctlp->errhp_ctl);

7. Set the number of arguments that will be passed to the SQL string with OCI_ATTR_NUM_COLS.

8. Get the column/attribute parameter list for the function context.

9. For each SQL string argument:

   1. Get the column descriptor for the object attribute with `OCI_DTYPE_PARAM`.

   2. The order in which the SQL string arguments are defined does not matter. The order does not have to match the order used in the SQL string.

   3. Set the attribute's column name with `OCI_ATTR_NAME`.

   4. There is a naming convention for SQL string arguments.

   5. The argument names must match the bind variable names used in the SQL string in content but not in case. For example, if the SQL string is "substr(:INPUT_STRING, 3, 5)", then it is acceptable if you give the argument name as "input_string".

   6. If an argument is used multiple times in an SQL string, declaring it once and counting it as one argument only is correct.

   7. Set the external column type (the type of the data that will be passed to the direct path API) with `OCI_ATTR_DATA_TYPE`.

   8. Set any other external column attributes (maximum data size, precision, scale, and so on).

   9. Free the handle to the column descriptor.

10. Set the function context `OCIDirPathFuncCtx` that was created in step 4 into the parent column object's parameter handle with OCI_ATTR_DIRPATH_FN_CTX.

#### Allocating the Column Array for SQL String Columns

When loading a SQL string column, the data for its arguments will be loaded into a separate column array created just for that SQL string column. A child column array is allocated for each SQL string column. Each row of arguments in the child column array maps back to the corresponding non-NULL row of its parent SQL string column in the parent column array.

To allocate a child column array for a SQL string column:

    OCIDirPathFuncCtx *dpfnctx;        /* direct path function context */
    OCIDirPathColArray *dpfnca;   /* direct path function column array */
    sword error;

    error = OCIHandleAlloc((dvoid *)dpfnctx, (dvoid **)&dpfnca,
                           OCI_HTYPE_DIRPATH_FN_COL_ARRAY,
                           (size_t)0, (dvoid **)0);

#### Loading the SQL String Data into the Column Array

If a column is scalar, its value would be set in the column array by passing the address of its value to `OCIDirPathColArrayEntrySet()`. If a column is of a SQL string type, the address of its child column array handle would be passed instead. The child column array would contain the SQL string's argument data.

To load data into a SQL string column:

Note: Steps that are different from loading scalar data are in italics.

For each SQL string column:

1. If the column is non-NULL:

   1. For each of its function argument columns:

      Set the data in the child column array using OCIDirPathColArrayEntrySet().

   2. Set the SQL string column's data into the column array by passing the address of its child column array handle to OCIDirPathColArrayEntrySet().

2. Else if the column is NULL:

   Set the SQL string column data into the column array by passing a NULL address for the data, a length of 0, and an `OCI_DIRPATH_COL_NULL` flag to `OCIDirPathColArrayEntrySet()`.

This process is similar to that for column objects.

See Also: "OCI_DIRPATH_COL_ERROR"

### Direct Path Loading of REF Columns

The REF type is a pointer, or reference, to a row object in an object table.

#### Describing the REF Column

Describing the arguments to a REF column is similar to describing the list of columns to be loaded for a table.

Note: A REF column can be a top-table-level column or nested as an object attribute to a column object. Steps that are different from loading scalar data are in italics.

1. Get a parameter handle on the REF column with `OCI_DTYPE_PARAM`. This parameter handle is used to set the column's external attributes.

2. Set the column name and its other external column attributes (for example, maximum data size, precision, scale).

3. Set the REF column's external type as SQLT_REF with OCI_ATTR_DATA_TYPE.

4. Allocate a direct path function context handle. This context is used to describe the REF column's arguments.

       OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
       sword error;

       error = OCIHandleAlloc((dvoid *)dpctx, (dvoid **)&dpfnctx,
                              OCI_HTYPE_DIRPATH_FN_CTX,
                              (size_t)0, (dvoid **)0);

5. OPTIONAL: Set the REF column's table name in OCI_ATTR_NAME in the function context. See the next step for more details.

       OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
       text *ref_tbl;     /* column's reference table */
       sword error;

       error = OCIAttrSet((dvoid *)dpfnctx,
                          OCI_HTYPE_DIRPATH_FN_CTX,
                          (dvoid *)ref_tbl, (ub4)strlen((const char *)ref_tbl),
                          OCI_ATTR_NAME, ctlp->errhp_ctl);

6. OPTIONAL: Set the expression type, OCI_ATTR_DIRPATH_EXPR_TYPE, to be OCI_DIRPATH_EXPR_REF_TBLNAME. Set this only if step 5 was done. This indicates that the expression set with OCI_ATTR_NAME will be used as the object table to reference row objects from. This parameter is optional. The behavior for this parameter varies for the REF type.

   - Unscoped REF columns (unscoped, system-OID-based):

     If not set, then by the definition of an "unscoped" REF column, this REF column is required to have a reference table name as its argument for every data row.

     If set, this REF column can only refer to row objects from this specified object table for the duration of the load. And the REF column is not allowed to have a reference table name as its argument. (The direct path API is providing this parameter as a short cut to users who will be loading to an unscoped REF column that refers to the same reference object table during the entire load.)

   - Scoped REF columns (scoped, system-OID-based and primary-key-based):

     If not set, the direct path API will use the reference table specified in the schema.

     If set, the reference table name must match the object table specified in the schema for this scoped REF column. An error occurs if the table names do not match.

     Whether this parameter is set or not, it does not matter to the API whether this reference table name is in the data row or not. If the name is in the data row, it has to match the table name specified in the schema. If it is not in the data row, the API will use the reference table specified in the schema.

7. Set the number of REF arguments that will be used to reference a row object. with OCI_ATTR_NUM_COLS. The number of arguments required varies for the REF column type. This number is derived from step 6 earlier.

   - Unscoped REF columns (unscoped, system-OID-based REF columns):

     One if OCI_DIRPATH_EXPR_REF_TBLNAME is used. None for the reference table name, and one for the OID value.

     Two if OCI_DIRPATH_EXPR_REF_TBLNAME is not used. One for the reference table name, and one for the OID value.

   - Scoped REF columns (scoped, system-OID-based and primary-key-based):

     N or N+1 are acceptable, where N is the number of columns making up the object id, regardless if OCI_DIRPATH_EXPR_REF_TBLNAME is used or not. Minimum is N if the reference table name is not in the data row. It's N+1 if the reference table name is in the data row. Note: If the REF is system-OID-based, then N is one. If the REF is primary-key-based, then N is the number of component columns that make up the primary key. If the reference table name is in the data row, then add one to N.

     Note: To simplify the error message if you were to pass in a number of REF arguments other than N or N+1, the error message will say that it found so-and-so number of arguments when it expects N. Although N+1 is not stated in the message, N+1 is acceptable (even though the reference table name is not needed) and will not invoke an error message.

8. Get the column/attribute parameter list for the function context.

9. For each REF argument or attribute:

   1. Get the column descriptor for the REF argument using `OCI_DTYPE_PARAM`.

   2. Set the attribute's column name using `OCI_ATTR_NAME`.

      The order of the REF arguments given matter. The reference table name comes first, if given. The object id, whether it is system-generated or primary-key-based, comes next.

      There is a naming convention for the REF arguments. Since the reference table name is not a table column, you can use any dummy names for its column name, such as "ref-tbl". For a system-generated OID column, you can use any dummy names for its column name, such as. "sys-OID". For a primary-key-based object id, list all the primary-key columns to load into. There is no need to create a dummy name for OID. The component column names, if given (see short cut note later), can be given in any order.

      Do not set the attribute column name(s) for the object id if you want to use the short cut.

      Short cut. If loading a system-OID-based REF column, do not set the column name with a name. The API will figure it out. But you will still have to set other column attributes, such as external datatype.

      If loading a primary-key REF column and its primary key consists of multiple columns, the short cut is not to set their column names. But you will still have to set other column attributes, such as external datatype.

      Note: If the component column names are NULL, then the API code determines the column names in the position or order in which they were defined for the primary key. So, when you set column attributes other than the name, make sure the attributes are set for the component columns in the correct order.

   3. Set the external column type (the type of the data that will be passed to the direct path API) using `OCI_ATTR_DATA_TYPE`.

   4. Set any other external column attributes (max data size, precision, scale, and so on).

   5. Free the handle to the column descriptor.

   6. Set the function context `OCIDirPathFuncCtx` that was created in step 4 in the parent column object's parameter handle using OCI_ATTR_DIRPATH_FN_CTX.

#### Allocating the Column Array for a REF Column

To allocate a child column array for a REF column:

    OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
    OCIDirPathColArray *dpfnca; /* direct path function column array */
    sword error;

    error = OCIHandleAlloc((dvoid *)dpfnctx, (dvoid **)&dpfnca,
                           OCI_HTYPE_DIRPATH_FN_COL_ARRAY,
                           (size_t)0, (dvoid **)0);

#### Loading the REF Data into the Column Array

If a column is scalar, its value would be set in the column array by passing the address of its value to `OCIDirPathColArrayEntrySet()`. If a column is a REF, the address of its child column array handle would be passed instead. The child column array will contain the REF arguments' data.

To load data into a REF column:

Note: Steps that are different from loading scalar data are in italics.

For each REF column:

1. If the column is non-NULL:

   1. For each of its REF argument columns:

      Set its data in the child column array using OCIDirPathColArrayEntrySet().

   2. Set the REF column's data into the column array by passing the address of its child column array handle to OCIDirPathColArrayEntrySet().

2. Else if the column is NULL:

   Set the REF column's data into the column array by passing a NULL address for the data, length of 0, and a `OCI_DIRPATH_COL_NULL` flag to `OCIDirPathColArrayEntrySet()`.

   See Also: "OCI_DIRPATH_COL_ERROR"

### NOT FINAL Object and REF Columns

An example of an inheritance hierarchy is shown in the following section.

#### Inheritance Hierarchy Diagram

In this example, `Person` is at the top of the hierarchy. It has two sub-types, `Employee` and `Student`. `ParttimeEmployee` is a sub-type of `Employee`. Therefore, the types which can be stored in a `Person` column are shown in this diagram:

    Person (Name, Address)
                    |            |
                    |            |
       Student(Units, GPA)      Employee (Manager, Deptid)
                                 |
                                 |
                                ParttimeEmployee (Hours)

When loading a table which contains a column of type `Person`, the actual set of types could include any of these four: the `NOT FINAL` type `Person`, and its three sub-types: `Student`, `Employee`, and `ParttimeEmployee`. The direct path API only supports the loading of one fixed, derived type to this `NOT FINAL` column for the duration of this load. Thus, the API needs to know which one of these types will be loaded, the attributes to load for this type, and the function used to create this type.

Note: A `NOT FINAL` column in a table can only store one fixed, derived type for the duration of the load. When describing and loading a derived type, all of the attributes for that type that are to be loaded must be specified. Think of a subtype as a flattened representation of all the object attributes that are unique to this type plus all the attributes of its ancestors. Therefore, any of these attribute columns that are to be loaded into will have to be described and counted. For example, if loading to all columns in `ParttimeEmployee`, there are 5 object attributes to load into: `Name`, `Address`, `Manager`, `Deptid`, and `Hours.`

#### Describing a Fixed, Derived Type to be Loaded

To describe a `NOT FINAL` or substitutable object and REF columns of a fixed, derived type:

Note: The steps describing a `NOT FINAL` column of a fixed, derived type is similar to describing its `FINAL` counterpart.

To describe a `NOT FINAL` column of type X (where X is object or REF), refer to previous sections to describe a `FINAL` column of this type. Because the derived type (could be a supertype or a subtype) is fixed for the duration of the load, the client interface for describing a `NOT FINAL` column is the same as for a `FINAL` column.

A subtype can be thought of as a flattened representation of all the object attributes that are unique to this type plus all the attributes of its ancestors. Therefore, any of these attribute columns that are to be loaded into will have to be described and counted.

#### Allocating the Column Array

This is the same as for a `FINAL` column of the same type.

#### Loading the Data into the Column Array

This is the same as for a `FINAL` column of the same type.

### Direct Path Loading of Object Tables

An object table is a table in which each row is an object (or row object). Each column in the table is an object attribute.

#### Describing an Object Table

Describing an object table is very similar to describing a non-object table. Each object attribute is a column in the table. The only difference is that you may need to describe the OID, which could be system-generated, user-generated, or primary-key based.

To describe an object table:

Note: Steps that are different from loading a non-object table are in italics.

For each object attribute column:

Describe each object attribute column as it needs to be described, depending on its type (for example, NUMBER, REF):

For the object table OID (Oracle Internet Directory):

1. If the object id is system-generated:

   Nothing extra to do. The system will generate OIDs for each row object.

2. If the object id is user-generated:

   1. Use a dummy name to represent the column name for the OID (for example, "cust_oid").

   2. Set the OID column attribute with OCI_ATTR_DIRPATH_OID.

3. If the object id is primary-key-based:

   1. All of the primary-key columns making up the OID must be loaded.

   2. Do not set OCI_ATTR_DIRPATH_OID, because no OID column with a dummy name was created.

#### Allocating the Column Array for the Object Table

This is the same as allocating a column array for a non-object table.

    OCIDirPathColArray *dpca;  /* direct path column array */
    sword error;

    error = OCIHandleAlloc((dvoid *)dpctx, (dvoid **)&dpca,
                           OCI_HTYPE_DIRPATH_COLUMN_ARRAY,
                           (size_t)0, (dvoid **)0);

#### Loading Data into the Column Array

This is the same as loading data into a non-object table.

### Direct Path Loading a NOT FINAL Object Table

A `NOT FINAL` object table supports inheritance and a `FINAL` object table cannot.

#### Describing a NOT FINAL Object Table

Describing a `NOT FINAL` object table of a fixed derived type is very similar to describing a `FINAL` object table.

To describe a `NOT FINAL` object table of a fixed derived type:

Note: Steps that are different from loading a FINAL object table are in italics.

1. Set the object table's object type in the direct path context with OCI_ATTR_DIRPATH_OBJ_CONSTR. This indicates that the object type, whether it is a supertype or a derived type, will be used as the default object constructor when loading to this table for the duration of the load.

       text *obj_type;            /* the object type to load into this NOT FINAL */
                                  /* object table */
       sword error;

       error = OCIAttrSet((dvoid *)dpctx,
                          OCI_HTYPE_DIRPATH_CTX,
                          (dvoid *) obj_type,
                          (ub4)strlen((const char *) obj_type),
                          OCI_ATTR_DIRPATH_OBJ_CONSTR, ctlp->errhp_ctl);

2. For each of the object attribute columns to be loaded, describe them according to their datatypes. Describe the object id, if needed. This is the same as describing a `FINAL` object table.

#### Allocating the Column Array for the NOT FINAL Object Table

This is the same as for a `FINAL` object table.

## Direct Path Loading in Pieces

To support loading data that will not all fit in memory at one time, use loading in pieces.

The direct path API already supports loading LONGs and LOBs incrementally. This is accomplished through the following sequence of steps:

1. Set the first piece into the column array using `OCIDirPathColArrayEntrySet()` and passing in the `OCI_DIRPATH_COL_PARTIAL` flag to indicate that all the data for this column has not been loaded yet.

2. Convert the column array to a stream.

3. Load the stream.

4. Set the next piece of that data into the column array. If it is not complete, set the partial flag and go back to step 2. If it is complete, then set the `OCI_DIRPATH_COL_COMPLETE` flagand continue on to the next column.

This approach is essentially the same for dealing with large attributes for column objects and large arguments for SQL string types.

See Also: "OCI_DIRPATH_COL_ERROR"

Note: Collections are not loaded in pieces, as such. Nested tables are loaded separately and are loaded like a top-level table. Nested tables can be loaded incrementally and can have columns which are loaded in pieces. Therefore, do not set the `OCI_DIRPATH_COL_PARTIAL` flag for the column containing the collection.

### Loading Object Types in Pieces

Objects are loaded into a separate column array from the parent table which contains them. Therefore, when they need to be loaded in pieces you must set the elements in the child column array up to and including the pieced element.

The general steps are:

1. For the pieced element, set the `OCI_DIRPATH_COL_PARTIAL` flag.

2. Set the child column array handle into the parent column array and mark that entry with the `OCI_DIRPATH_COL_PARTIAL` flag as well.

3. At this point, convert the parent column array to a stream. This will convert the child column array as well.

4. Then load the stream.

5. Go back to step one and continue loading the remaining data for that element until it is complete.

Here are some rules about loading in pieces:

- There can only be one partial element at a time at any level. Once one partial element is marked complete then another one at tht level could be partial.

- If an element is partial and it is not top-level, then all of its ancestors up the containment hierarchy must be marked partial as well.

- If there are multiple levels of nesting, it is necessary to go up to a level where the data can be converted into a stream. This will be a top-level table.

See Also: "OCI_DIRPATH_COL_ERROR"

## Direct Path Context Handles and Attributes for Object Types

The following discussion gives the supplemental details of the handles and attributes that are listed in the appendix A.

### Direct Path Context Attributes

There is one.

#### OCI_ATTR_DIRPATH_OBJ_CONSTR

Indicates the object type to load into a `NOT FINAL` object table.

    ttext *obj_type;            /* the object type to load into this NOT FINAL */
                               /* object table */
    sword error;

    error = OCIAttrSet((dvoid *)dpctx,
                       OCI_HTYPE_DIRPATH_CTX,
                       (dvoid *) obj_type,
                       (ub4)strlen((const char *) obj_type),
                       OCI_ATTR_DIRPATH_OBJ_CONSTR, ctlp->errhp_ctl);

### Direct Path Function Context and Attributes

Here is a summary of the attributes for function context handles.

See Also: "Direct Path Context Handle (OCIDirPathCtx) Attributes"

#### OCI_ATTR_DIRPATH_OBJ_CONSTR

Indicates the object type to load into a substitutable object table.

    text *obj_type; /* stores an object type name */
    sword error;

    error = OCIAttrSet((dvoid *)dpctx,
                       OCI_HTYPE_DIRPATH_CTX,
                       (dvoid *) obj_type,
                       (ub4)strlen((const char *) obj_type),
                       OCI_ATTR_DIRPATH_OBJ_CONSTR, ctlp->errhp_ctl);

#### OCI_ATTR_NAME

When a function context is created, set `OCI_ATTR_NAME` equal to the expression that describes the non-scalar column. Then set an OCI attribute to indicate the type of the expression. The expression type varies as follows:

1. Column objects:

   1. This required expression is the object type name. The object type will be used as the default object constructor.

   2. Set the expression type `OCI_ATTR_DIRPATH_EXPR_TYPE` to `OCI_DIRPATH_EXPR_OBJ_CONSTR` to indicate this expression is an object type name.

2. REF columns:

   1. This optional expression is the reference table name. This table is the object table from which the REF column will be referencing row objects.

   2. Set the expression type `OCI_ATTR_DIRPATH_EXPR_TYPE` to `OCI_DIRPATH_EXPR_REF_TBLNAME` to indicate this expression is a reference object table.

   3. The behavior for this parameter, set or not set, varies for each REF type.

      - Unscoped REF columns (unscoped, system-OID-based):

      - If not set, then by the definition of an "unscoped" REF column, this REF column is required to have a reference table name as its argument for every data row.

      - If set, this REF column can only refer to row objects from this specified object table for the duration of the load. And the REF column is not allowed to have a reference table name as its argument. (Direct path API is providing this parameter as a short cut to the users who will be loading to an unscoped REF column that refers to the same reference object table during the entire load.)

      - Scoped REF columns (scoped, system-OID-based and primary-key-based):

      - If not set, the direct path API will use the reference table specified in the schema.

      - If set, the reference table name must match the object table specified in the schema for this scoped REF column. An error occurs if the table names do not match.

      - Whether this parameter is set or not, it will not matter to the API whether this reference table name is in the data row or not. If the name is in the data row, it has to match the table name specified in the schema. If it is not in the data row, the API will use the reference table defined in the schema.

3. SQL string columns:

   This mandatory expression contains a SQL string to derive the value that will be stored in the column.

   Set the expression type `OCI_ATTR_DIRPATH_EXPR_TYPE` to `OCI_DIRPATH_EXPR_SQL` to indicate that this expression is a SQL string.

#### OCI_ATTR_DIRPATH_EXPR_TYPE

This attribute is used to indicate the type of the expression specified in `OCI_ATTR_NAME` for the non-scalar column's function context.

If `OCI_ATTR_NAME` is set, then `OCI_ATTR_DIRPATH_EXPR_TYPE` is required.

The possible values for `OCI_ATTR_DIRPATH_EXPR_TYPE` are:

1. `OCI_DIRPATH_EXPR_OBJ_CONSTR`

   - Indicates that the expression is an object type name and will be used as the default object constructor for a column object.

   - Required for column objects.

2. `OCI_DIRPATH_EXPR_REF_TBLNAME`

   - Indicates that the expression is a reference object table name. This table is the object table from which the REF column will be referencing row objects.

   - Optional for REF columns.

3. `OCI_DIRPATH_EXPR_SQL`

   - Indicates that the expression is a SQL string, which is executed to derive a value to be stored in the column.

   - Required for SQL string columns.

The following pseudocode example illustrates the preceding rules:

    OCIDirPathFuncCtx  *dpfnctx; /* function context for this non-scalar column */
    ub1 expr_type; /* expression type */
    sword error;

    if (...) /* (column type is an object) */
    expr_type = OCI_DIRPATH_EXPR_OBJ_CONSTR;
    ...
    if (...) /* (column_type is a REF && function context name exists) */
    expr_type = OCI_DIRPATH_EXPR_REF_TBLNAME;
    ...
    if (...) /* (column_type is a SQL string) */
    expr_type = OCI_DIRPATH_EXPR_SQL;
    ...
    error = OCIAttrSet((dvoid *)(dpfnctx),
                       OCI_HTYPE_DIRPATH_FN_CTX,
                       (dvoid *)&expr_type, (ub4)0,
                       OCI_ATTR_DIRPATH_EXPR_TYPE, ctlp->errhp_ctl);

#### OCI_ATTR_NUM_COLS

This attribute describes the number of attributes or arguments that will be loaded or processed for a non-scalar column. This parameter must be set before the column list can be retrieved.

1. Column objects:

   The number of object attribute columns to be loaded for this column object.

2. SQL string columns:

   1. The number of arguments to be passed to the SQL string.

   2. If an argument is used multiple times in the function, counting it as one is correct.

3. REF columns:

   1. The number of REF arguments to identify the row object the REF column should point to.

   2. The number of arguments required varies for the REF column type:

   - Unscoped REF columns (unscoped, system-OID-based REF columns):

     If `OCI_DIRPATH_EXPR_REF_TBLNAME` is used. None for the reference table name, and one for the OID value. (Only the OID values will be in the data rows.)

     If `OCI_DIRPATH_EXPR_REF_TBLNAME` is not used. One for the reference table name, and one for the OID value. (Both the reference table names and the OID values will be in the data rows.)

   - Scoped REF columns (scoped, system-OID-based and primary-key-based):

     N or N+1 are acceptable, where N is the number of columns making up the object id, regardless if `OCI_DIRPATH_EXPR_REF_TBLNAME` is used or not. The minimum is N if the reference table name is not in the data row. Use N+1 if the reference table name is in the data row.

     If the REF is system-OID-based, then N is one. If the REF is primary-key-based, then N is the number of component columns that make up the primary key. If the reference table name is in the data row, then add one to N.

Note: To simplify the error message if you pass in a number of REF arguments other than N or N+1, the error message will say that it found so-and-so number of arguments when it expects N. Although N+1 is not stated in the message, N+1 is acceptable (even though the reference table name is not needed) and will not invoke an error message.

#### OCI_ATTR_NUM_ROWS

This attribute, when used for a `OCI_HTYPE_DIRPATH_FN_CTX` (function context), is retrievable only, and cannot be set by the user. You can only use this attribute in `OCIAttrGet()` and not `OCIAttrSet()`. When called with `OCIAttrGet()`, the number of rows loaded so far is returned.

However, the attribute `OCI_ATTR_NUM_ROWS`, when used for a `OCI_HTYPE_DIRPATH_CTX` (table-level context), can be set and can be retrieved by the user.

Calling `OCIAttrSet()` with `OCI_ATTR_NUM_ROWS` and `OCI_HTYPE_DIRPATH_CTX` sets the number of rows to be allocated for the table-level column array. If not set, the direct path API code will derive a "reasonable" number based on the maximum record size and the transfer buffer size. To see how many rows were allocated, call `OCIAttrGet()` with `OCI_ATTR_NUM_ROWS` on `OCI_HTYPE_DIRPATH_COLUMN_ARRAY` for a table-level column array, and with `OCI_HTYPE_DIRPATH_FN_COL_ARRAY` for a function column array.

Calling `OCIAttrGet()` with `OCI_ATTR_NUM_ROWS` and `OCI_HTYPE_DIRPATH_CTX` returns the number of rows loaded so far.

This attribute cannot be set by the user for a function context. You are not allowed to specify the number of rows desired in a function column array through `OCI_ATTR_NUM_ROWS` with OCIAttrSet() because then all function column arrays will have the same number of rows as the table-level column array. Thus this attribute can only be set for a table-level context and not for a function context.

### Direct Path Column Parameter Attributes

When describing an object, SQL string, or REF column, one of its column attributes is a function context.

If a column is an object, then its function context describes its object type and object attributes. If a SQL string, the expression to be called. If REF, its reference table name and row object identifiers.

When setting a function context as a column attribute, `OCI_ATTR_DIRPATH_FN_CTX` is used in `OCIAttrSet()`:

    OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
    sword error;

    error = OCIAttrSet((dvoid *)colDesc,
                       OCI_DTYPE_PARAM,
                       (dvoid *)(dpfnctx), (ub4)0,
                       OCI_ATTR_DIRPATH_FN_CTX, ctlp->errhp_ctl);

Attributes for column parameter context handles follow.

See Also: "Direct Path Column Parameter Attributes"

#### OCI_ATTR_NAME

The naming conventions when loading nested tables, object tables, SQL string columns, and REF columns are described in the following paragraphs.

In general, a dummy column name is used if are loading data into a column that is a system column with a system name that you are not aware of (for example, an object table's system-generated object id (`OID`) column or a nested table's `SETID` (`SID`) column) or if a column is an argument that doesn't have a database table column (for example, SQL string and REF arguments).

If the column is a database table column, but a dummy name was used, then a column attribute has to be set so that the function can identify the column even though it's not under the name known to the database.

The naming rules are:

1. Child nested tables's `SETID` (`SID`) column:

   The SETID column is required. Set its `OCI_ATTR_NAME` using a dummy name, because the API doesn't expect the user to know its system name. Then set the column attribute with `OCI_ATTR_DIRPATH_SID` to indicate that this is a `SID` column.

2. Object table's object id (`OID`) column:

   An object id is required if:

   1. If the object id is system-generated:

      Use a dummy name as its column name (for example, "cust_oid").

      Set its column attribute with `OCI_ATTR_DIRPATH_OID`. So if you have multiple columns with dummy names, you know which one represents the system-generated `OID`.

   2. If the object id is primary-key-based:

      You cannot use a dummy name as its column name. Therefore, you do not need to set its column attribute with `OCI_ATTR_DIRPATH_OID`.

3. SQL string argument:

   Set the attribute's column name with `OCI_ATTR_NAME`.

   The order of the SQL string arguments given does not matter. The order does not have to match the order used in the SQL string.

   There is a naming convention for SQL string arguments.

   1. The argument names must match the bind variable names used in the SQL string in content but not in case. For example, if the SQL string is `substr(:INPUT_STRING, 3, 5)`, then you can give the argument name as "input_string".

   2. If an argument is used multiple times in an SQL string, then you can declare it once and count it as only one argument.

4. REF argument:

   1. Set the attribute's column name using `OCI_ATTR_NAME`.

      The order of the REF arguments does matter.

      - The reference table name comes first, if given.

      - The object id, whether it is system-generated or primary-key-based, comes next.

   2. There is a naming convention for the REF arguments.

      - For the reference table name argument, use any dummy names for its column name, for example, "ref-tbl".

      - For the system-generated OID argument, use any dummy names for its column name, such as "sys-OID". Note: Since this column is used as an argument and not as a column to load into, do not set this column with `OCI_ATTR_DIRPATH_OID`.

      - For a primary-key-based object id, list all the primary-key columns to load into. There is no need to create a dummy name for OID. The component column names, if given (see step for short cut later), can be given in any order.

   3. Do not set the attribute column name(s) for the object id if you want to use the short cut.

   - Short cut. If loading a system-OID-based REF column, do not set the column name with a name. The API will figure it out. But you still have to set other column attributes, such as external datatype.

   - If loading a primary-key REF column and its primary key consists of multiple columns, the short cut is not to set their column names. But user will still have to set other column attributes, such as external datatype.

     Note: If the component column names are NULL, then the API code determines the column names in the position or order in which they were defined for the primary key. So, when you set column attributes other than the name, make sure the attributes are set for the component columns in the correct order.

#### OCI_ATTR_DIRPATH_SID

Indicates that a column is a nested table's `SETID` column. Required if loading to a nested table.

    ub1 flg = 1;
    sword error;

    error = OCIAttrSet((dvoid *)colDesc,
                       OCI_DTYPE_PARAM,
                       (dvoid *)&flg, (ub4)0,
                       OCI_ATTR_DIRPATH_SID, ctlp->errhp_ctl);

#### OCI_ATTR_DIRPATH_OID

Indicates that a column is an object table's object id column.

    ub1 flg = 1;
    sword error;

    error = OCIAttrSet((dvoid *)colDesc,
                       OCI_DTYPE_PARAM,
                       (dvoid *)&flg, (ub4)0,
                       OCI_ATTR_DIRPATH_OID, ctlp->errhp_ctl);

### Direct Path Function Column Array Handle for Non-scalar Columns

See Also: "Direct Path Function Column Array Handle (OCIDirPathColArray) Attributes"

The handle type `OCI_HTYPE_DIRPATH_FN_COL_ARRAY` is used if the column is an object, SQL string, or REF. The structure `OCIDirPathColArray` is the same for both scalar and non-scalar columns.

To allocate a child column array for a function context:

    OCIDirPathFuncCtx *dpfnctx; /* direct path function context */
    OCIDirPathColArray *dpfnca; /* direct path function column array */
    sword error;

    error = OCIHandleAlloc((dvoid *)dpfnctx, (dvoid **)&dpfnca,
                           OCI_HTYPE_DIRPATH_FN_COL_ARRAY,
                           (size_t)0, (dvoid **)0);

#### OCI_ATTR_NUM_ROWS Attribute

This attribute, when used for a `OCI_HTYPE_DIRPATH_FN_COL_ARRAY` (function column array), is retrievable only, and cannot be set by the user. When called with the function `OCIAttrGet()`, the number of rows allocated for the function column array is returned.